# -*-coding: utf-8 -*-
"""
作者：TianyiFan
日期：2023-年06-月20日
用途：双层码头的主函数
"""
import sys
from tabulate import tabulate
from gurobi_model import optimal_model      # gurobi求解
from cplex_model  import docplex_model      # docplex求解
from benders_model import bender_solution   # benders算法
from heuristic_rule import *                # 初始解求解
from common_fuc import *
# from CG_main import CG_function             # CG运行主框架
# from para import common_func                # 依赖于参数的通用模块
from CG_Model import plan_poor                # CG 计划的类　
from swo_algo_method import swo_algo_fuc
from batch_model import new_swo_fuc
from test import test_reload

if __name__ =="__main__":
    solution_display = pd.DataFrame()  # 统计算例结果的数据
    col_initial_value = []
    col_swo_value = []
    col_swo_time = []
    col_batch_value=[]
    col_batch_time=[]
    col_cplex_value = []
    col_cplex_time =[]
    col_cplex_LB = []
    col_cplex_LB_time = []
    col_gap_rule_MH = []
    col_gap_SWO = []
    col_gap_batch = []
    col_gap_LB_BAT = []
    col_gap_LB = []
    col_seed = []
    col_scale = []
    col_cplex_compare = []
    col_time_set = []
    col_gap_benefit = []
    # 分割线---------------------------------------------------------------------------
    analysis_solution = pd.DataFrame()  # 统计敏感性分析实验结果的数据
    col_m0_cost_t = []
    col_m0_cost_p = []
    col_m0_cost_u = []
    col_m1_cost_t = []
    col_m1_cost_p = []
    col_m1_cost_u = []
    col_gurobi_value = []
    col_gurobi_time =[]

    # 代码调试开关---------------------------------------------------------------------------
    button_params = 0
    # 分割线---------------------------------------------------------------------------------

    # 测试单元开关--------------------------------------------------------------------------
    test_rule = 0
    test_swo = 0
    test_batch_model = 0
    test_cplex_LB = 0
    test_new_model = 0
    test_cplex = 0
    test_gurobi_LP = 0
    test_gurobi_LB = 0
    test_gurobi = 1
    test_benders = 0
    test_analysze_mode = 1
    # 分割线---------------------------------------------------------------------------------
    problem_scale = 0
    seed_start = 20
    seed_end = seed_start+1
    total_seed_set = [i for i in range(seed_start,seed_end)]       # 　测试指定算例模式
    # total_seed_set = [91,92]                                     #　　循环测试算例模式
    remain_test_set = copy.deepcopy(total_seed_set)
    params.size_change(problem_scale)                              # 修改测试算例的问题规模
    with open('experient_info.txt', 'w') as file:
        file.write('')
        print("测试单元算法执行情况：", file=file)
        print(f"rule       = {test_rule}", file=file)
        print(f"LB_model   = {test_cplex_LB}", file=file)
        print(f"batch_mode = {test_batch_model}", file=file)
        print(f"CPLEX      = {test_cplex}", file=file)
        print(f"Analysis   = {test_analysze_mode}",file=file)
        print("问题规模：ISG={}  V = {} K ={}  G = {}  Pair_N={}".format(problem_scale, params.V, params.K1, params.G, params.pair_new), file=file)
        print("测试算例集:", total_seed_set, file=file)

    for seed_input in total_seed_set:
        params.change_seed(seed_input)
        if seed_input not in remain_test_set:
            continue
        else:
            remain_test_set.remove(seed_input)
        start_para = 45
        inter_Val = 30
        end_para = start_para+inter_Val
        # step 1: 初始化参数和集合规模
        print("\n---------参数初始化-----------")
        params.initialization()
        params.set_generation()
        print("问题规模与参数：ISG={} seed={}  V = {} K ={}  G = {}  len(c_ui)={}  Pair_N={}".format(problem_scale, params.seed, params.V, params.K1, params.G, len(params.c_ui),
                                                                                                    params.pair_new))
        # step2: 参数输出
        params.print_info()
        # 修改某个参数的内循环
        for i in range(start_para, end_para, 5):
            x1 = i
            x2 = 180 - x1
            params.analysis_time(x1, x2)
            col_seed.append(seed_input)
            col_scale.append("ISG-{}".format(problem_scale))
            col_time_set.append("{}-{}".format(x1, x2))
            with open('experient_info.txt', 'a') as file:
                print("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", file=file)
                print("当前执行的敏感性实验中，time_u={}  time_p ={}：".format(x1, x2), file=file)
            # 分割线---------------------------------------------------------------------------
            if button_params==1:
                stop_cmd = input("是否继续运行代码？")
            # step3: 初始解
            rule_solution = initial_solution()  # 初始化初始解的类对象
            if test_rule == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>>>>初始解算法启动>>>>>>>>>>>>>>>>>>>>>>>")
                # print(params.test_data.data)  # 输出轮船的信息
                rule_solution.rule_heuristic()  # 计算初始解决策结果
            rule_value = rule_solution.obj
            col_initial_value.append(remain_two(rule_value))
            base = plan_poor()  # 初始化记录全局计划的数组
            # rule_solution.updata_rmp_plan(base,0)    # 将初始解更新到CG的第一个计划池中
            params.iter_count += 1

            # 分割线---------------------------------------------------------------------------
            base_swo = plan_poor()
            swo_solution = swo_algo_fuc()   # 算法初始化
            if test_swo == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>>>>SWO算法启动>>>>>>>>>>>>>>>>>>>>>>>")
                swo_solution.swo_main_main()  # 运行SWO算法主程序
            swo_value = swo_solution.solution_rd.obj
            swo_time = swo_solution.solving_time
            col_swo_value.append(remain_two(swo_value))
            col_swo_time.append(remain_two(swo_time))
            # for i in range(params.V+2):
            #     params.set_vessel[i] = params.iter_count  # 初始计划池的长度应当和当前的初始解的个数一致
            # 分割线---------------------------------------------------------------------------

            # step4:docplex 模型求解
            dcpl_model = docplex_model()
            if test_cplex_LB == 1:
                print("\n>>>>>>>>>docplex_Lower_bound model启动>>>>>>>>>>>>>>>>>>>>>>>")
                dcpl_model.build_lower_bound_model("lower_bound_cplex")

            cplex_lb_value = dcpl_model.obj_lb
            cplex_lb_time = dcpl_model.solving_time_lb
            col_cplex_LB.append(remain_two(cplex_lb_value))
            col_cplex_LB_time.append(remain_two(cplex_lb_time))

            # 分割线---------------------------------------------------------------------------
            batch_model_method = new_swo_fuc()
            if test_batch_model == 1:
                print(f"\n>>>>>>>>>>>>>>>>>>>>>>batch_model启动  当前算例={seed_input}>>>>>>>>>>>>>>>>>>>>>>>")
                batch_model_method.operate_main_fuc(dcpl_model.lb_cost_i,cplex_lb_value)
            batch_value = batch_model_method.obj
            batch_time = batch_model_method.solving_time
            col_batch_value.append(remain_two(batch_value))
            col_batch_time.append(remain_two(batch_time))
            temp_gamma_ik = batch_model_method.solution_rd.gamma_ik
            button_111 = 0
            if button_111==1:
                stop_cmd = input("代码是否继续运行")

            if test_cplex == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>docplex 求解启动>>>>>>>>>>>>>>>>>>>>>>>")
                dcpl_model.build_model("cplex_model",problem_scale=problem_scale)
            cplex_value = dcpl_model.obj
            cplex_time = dcpl_model.solving_time
            col_cplex_value.append(remain_two(cplex_value))
            col_cplex_time.append(remain_two(cplex_time))

            if test_new_model==1:
                print("\n>>>>>>>>>docplex_test_model model启动>>>>>>>>>>>>>>>>>>>>>>>")
                dcpl_model.build_compare_model("compare_cplex", problem_scale=problem_scale)
            cplex_compare_value = dcpl_model.obj_compare
            cplex_compare_time = dcpl_model.solving_time_compare
            col_cplex_compare.append(remain_two(cplex_compare_value))

            gap_benefit = (cplex_compare_value-cplex_value)/cplex_compare_value * 100
            if test_new_model ==1 and test_cplex==1:
                col_m0_cost_t.append(dcpl_model.cplex_output[0])
                col_m0_cost_p.append(dcpl_model.cplex_output[1])
                col_m0_cost_u.append(dcpl_model.cplex_output[2])
                col_m1_cost_t.append(dcpl_model.compare_output[0])
                col_m1_cost_p.append(dcpl_model.compare_output[1])
                col_m1_cost_u.append(dcpl_model.compare_output[2])
                col_gap_benefit.append(remain_two(gap_benefit))
            if test_analysze_mode ==1 and test_cplex ==1:
                col_m0_cost_t.append(dcpl_model.cplex_output[0])
                col_m0_cost_p.append(dcpl_model.cplex_output[1])
                col_m0_cost_u.append(dcpl_model.cplex_output[2])
            # if test_new_model ==1:
            #     print("\n---------new test model 求解启动-----------")
            #     dcpl_model.build_new_model()
            # print("new test_model  obj ={}  solve_time = {}".format(dcpl_model.obj,dcpl_model.solving_time))
            # stop_cmd = input("代码是否继续运行")
            # 分割线---------------------------------------------------------------------------

            # step4: gurobi模型求解
            gurobi_model = optimal_model("IP")
            if test_gurobi == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>Gurobi 求解启动>>>>>>>>>>>>>>>>>>>>>>>")
                gurobi_model.build_model()
            gurobi_value = gurobi_model.obj
            gurobi_time = gurobi_model.solving_time
            if test_analysze_mode == 1 and test_gurobi == 1:
                col_m0_cost_t.append(gurobi_model.gurobi_output[0])
                col_m0_cost_p.append(gurobi_model.gurobi_output[1])
                col_m0_cost_u.append(gurobi_model.gurobi_output[2])
                col_gurobi_value.append(remain_two(gurobi_model.obj))
                col_gurobi_time.append(gurobi_model.solving_time)

            if test_gurobi_LP == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>Gurobi_LP 求解启动>>>>>>>>>>>>>>>>>>>>>>>")
                gurobi_model.build_relax_model()
            gurobi_value_LP = gurobi_model.obj_LP
            gurobi_time_LP = gurobi_model.solving_time

            if test_gurobi_LB == 1:
                print("\n>>>>>>>>>>>>>>>>>>>>>>Gurobi_LB 求解启动>>>>>>>>>>>>>>>>>>>>>>>")
                gurobi_model.build_lower_bound_model()
            gurobi_value_lb = gurobi_model.obj_LB
            gurobi_time_LB = gurobi_model.solving_time_LB
            # 分割线---------------------------------------------------------------------------

            bender_method = bender_solution(gurobi_value_lb, gurobi_model.optimal_rd)
            if test_benders == 1:
                print("\n>>>>>>>>>benders algorithm 求解启动(基于gurobi)>>>>>>>>>>>>>>>>>")
                bender_method.operate_benders()
            benders_value = bender_method.obj
            benders_time = bender_method.solving_time
            # 分割线---------------------------------------------------------------------------

            if test_cplex == 1:  # 计算cplex和lower_bound 的差距
                gap_LB = round((cplex_value - gurobi_value_lb) / cplex_value * 100, 2)
            else:
                gap_LB = round((gurobi_value - gurobi_value_lb) / gurobi_value * 100, 2)
            gap_LB_Bat = round((batch_value - cplex_lb_value) / batch_value * 100, 2)
            gap_rule_MH = round((rule_value - batch_value) / rule_value * 100, 2)
            gap_rule_cpl = round((rule_value - cplex_value) / rule_value * 100, 2)
            gap_docplex = round((cplex_value - gurobi_value) / cplex_value * 100, 2)
            gap_benders = round((benders_value - gurobi_value) / benders_value * 100, 2)
            if test_rule == 1:
                print("initial_value=   {:10.2f}".format(rule_value))
            if test_swo == 1:
                print("SWO_value    =   {:10.2f}   SWO_time       = {:.2f} s ".format(swo_value, swo_time))
            if test_batch_model == 1:
                print("batch_value  =   {:10.2f}   batch_time     = {:.2f} s ".format(batch_value, batch_time))
            if test_cplex == 1:
                print("cplex_value  =   {:10.2f}   cplex_time     = {:.2f} s".format(cplex_value, cplex_time))
                gap_SWO = round((swo_value - cplex_value) / swo_value * 100, 2)
                gap_batch =  round((batch_value - cplex_value) / batch_value * 100, 2)
            else:
                gap_SWO = round((swo_value - gurobi_value) / swo_value * 100, 2)
                gap_batch = round((batch_value - gurobi_value) / batch_value * 100, 2)
            if test_gurobi == 1:
                print("gurobi_value =   {:10.2f}   gurobi_time    = {:.2f} s".format(gurobi_value, gurobi_time))
            if test_gurobi_LB == 1:
                print("gurobi_LB    =   {:10.2f}   gurobi_LB_time = {:.2f} s".format(gurobi_value_lb, gurobi_time_LB))
            if test_cplex_LB == 1:
                print("cplex_LB     =   {:10.2f}   cplex_LB_time  = {:.2f} s".format(cplex_lb_value, cplex_lb_time))
                gap_LB = round((cplex_value - cplex_lb_value) / cplex_value * 100, 2)
                gap_LB_Bat = round((batch_value - cplex_lb_value) / batch_value * 100, 2)
            if test_new_model ==1:
                print("compare_md   =   {:10.2f}   compare_time   = {:.2f} s".format(cplex_compare_time, cplex_compare_time))
            # print("gurobi_LP    =   {:10.2f}   gurobi_LP_time = {:.2f} s".format(gurobi_value_LP, gurobi_time_LP))
            # print("benders_al   =   {:10.2f}   benders_time   = {:.2f} s".format(benders_value,benders_time))
            col_gap_rule_MH.append(gap_rule_MH)
            col_gap_LB.append(gap_LB)
            col_gap_LB_BAT.append(gap_LB_Bat)
            col_gap_SWO.append(gap_SWO)
            col_gap_batch.append(gap_batch)
            print("rule   vs SWO_AL        = {} %".format(gap_rule_MH))
            print("batch  vs Cplex/gurobi  = {} %".format(gap_batch))
            print("batch vs Lower_bound   = {} %".format(gap_LB_Bat))
            print("opt_So vs Lower_bound   = {} %".format(gap_LB))
            print("seed = {}".format(params.seed))
            with open('experient_info.txt', 'a') as f:
                print('当前测试算例:[{}] 概要信息： Obj_LB={:.2f}  Obj_batch={:.2f}   T_batch={:.2f}   T_cplex={:.2f}   gap_rule_MH={}%    gap_batch={}%    gap_LB_Bat={}%'.
                      format(seed_input, cplex_lb_value,batch_value, batch_time, cplex_time, gap_rule_MH, gap_batch, gap_LB_Bat), file=f)
                wait_seed = [i for i in range(seed_input + 1, seed_end)]
                if len(wait_seed) == 0:
                    print("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", file=f)
                    print("所有算例：{} 均已完成！！！".format(total_seed_set), file=f)
                else:
                    print("待完成测试算例：{}".format(remain_test_set), file=f)

            # print("cplex  vs Gurobi    = {} %".format(gap_docplex))
            # print("BD_AL  vs Gurobi    = {} %".format(gap_benders))

    # 输出算例实验结果
    solution_display['ISG'] = col_scale
    solution_display['seed'] = col_seed
    solution_display['obj_LoweB'] = col_cplex_LB
    solution_display['T_LB'] = col_cplex_LB_time
    if test_cplex==1:
        solution_display['Obj_Cplex'] = col_cplex_value
        solution_display['T_cpl'] = col_cplex_time
    elif test_gurobi==1:
        solution_display['Obj_Gurobi'] = col_gurobi_value
        solution_display['T_Gurobi'] = col_gurobi_time
    solution_display['Obj_batch'] = col_batch_value
    solution_display['T_batch'] = col_batch_time
    solution_display['Obj_Rule'] = col_initial_value
    solution_display['gap_rule_MH(%)'] = col_gap_rule_MH  # 规则比算法
    solution_display['gap_batch_cpl(%)'] = col_gap_batch  # 算法比最优解
    solution_display['gap_BAT_LB(%)'] = col_gap_LB_BAT    # 算法比LB_value
    solution_display['gap_cplex_LB(%)'] = col_gap_LB      # 最优解比LB_value
    solution_display['Obj_compare_md'] = col_cplex_compare  # 对比模型的值
    solution_display.to_excel(sheet_name="sheet1", excel_writer="solution_output.xlsx", index=False)
    # 输出异层转运收益实验结果
    if test_new_model==1:
        analysis_solution['ISG'] = col_scale
        analysis_solution['seed'] = col_seed
        analysis_solution['m0_cost_t'] = col_m0_cost_t
        analysis_solution['m0_cost_p'] = col_m0_cost_p
        analysis_solution['m0_cost_u'] = col_m0_cost_u
        analysis_solution['m1_cost_t'] = col_m1_cost_t
        analysis_solution['m1_cost_p'] = col_m1_cost_p
        analysis_solution['m1_cost_u'] = col_m1_cost_u
        analysis_solution['Obj_Cplex'] = col_cplex_value
        analysis_solution['Obj_compare_md'] = col_cplex_compare
        analysis_solution['gap_benefits'] = col_gap_benefit  # 对比模型的最优解
        with pd.ExcelWriter("solution_output.xlsx",mode='a') as writer:
            analysis_solution.to_excel(sheet_name="sheet2", excel_writer=writer, index=False)
    if test_analysze_mode ==1:
        analysis_solution['ISG'] = col_scale
        analysis_solution['seed'] = col_seed
        analysis_solution['factor'] = col_time_set
        analysis_solution['m0_cost_t'] = col_m0_cost_t
        analysis_solution['m0_cost_p'] = col_m0_cost_p
        analysis_solution['m0_cost_u'] = col_m0_cost_u
        analysis_solution['Obj_solution'] = col_gurobi_value
        with pd.ExcelWriter("solution_output.xlsx",mode='a') as writer:
            analysis_solution.to_excel(sheet_name="sheet2", excel_writer=writer, index=False)

    print("算例-{} DS={} step={} 结果如下：".format(col_seed, params.search_DS, params.step_DS))
    print_pd(solution_display)
    with open('experient_info.txt', 'a') as f:
        print("\n数值实验结果>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",file=f)
        print(solution_display,file=f)
        if test_analysze_mode==1:
            print("敏感性实验结果>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",file=f)
            # print(analysis_solution, file=f)
            table = tabulate(analysis_solution, headers='keys', tablefmt='grid')
            f.write(table)
    sys.exit()

    #
    # base_gurobi = plan_poor()                                       # 记录gurobi求解结果的plan_poor
    # base_gurobi = common_func.update_plan_pool(base_gurobi)         # 更新base_gurobi
    # # step5: CG算法模块
    # CG_start = time.time()
    # CG_solution = CG_function(base_swo)l
    # CG_end = time.time()
    # gap1 = round((CG_solution - gurobi_value) / gurobi_value * 100, 2)
    # gap2 = round((initial_value - gurobi_value) / gurobi_value * 100, 2)
    # print(f'gurobi_model = {gurobi_value:.2f}   CG_value = {CG_solution:.2f}   rule_value = {initial_value}    gap1 = {gap1} %  gap2 = {gap2} %')
    # print(" 求解时间: gurobi = {:.2f} s  CG = {:.2f} s   ".format(end_time-start_time,CG_end-CG_start))






